#include "stdafx.h"

#include "json/jsoncpp/assertions.hpp"
#include "json/jsoncpp/value.hpp"
#include "json/jsoncpp/writer.hpp"
#include <math.h>
#include <sstream>
#include <utility>
#include <cstring>
#include <cassert>
#include <cstddef> // size_t
#include <algorithm> // min()

#define JSON_ASSERT_UNREACHABLE assert(false)
#pragma warning(disable:4715)

namespace JHCPP
{
	namespace json
	{
		namespace jsoncpp
		{
			// This is a walkaround to avoid the static initialization of Value::null.
			// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
			// 8 (instead of 4) as a bit of future-proofing.
			#define ALIGNAS(byte_alignment)

			static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
			const unsigned char& kNullRef = kNull[0];
			const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
			const Value& Value::nullRef = null;

			const Int Value::minInt = Int(~(UInt(-1) / 2));
			const Int Value::maxInt = Int(UInt(-1) / 2);
			const UInt Value::maxUInt = UInt(-1);
		#if defined(JSON_HAS_INT64)
			const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
			const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
			const UInt64 Value::maxUInt64 = UInt64(-1);
			// The constant is hard-coded because some compiler have trouble
			// converting Value::maxUInt64 to a double correctly (AIX/xlC).
			// Assumes that UInt64 is a 64 bits integer.
			static const double maxUInt64AsDouble = 18446744073709551615.0;
		#endif // defined(JSON_HAS_INT64)
			const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
			const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
			const LargestUInt Value::maxLargestUInt = LargestUInt(-1);

		#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
			template <typename T, typename U>
			static inline bool InRange(double d, T min, U max) {
				return d >= min && d <= max;
			}
		#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
			static inline double integerToDouble(UInt64 value) {
				return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
			}

			template <typename T> static inline double integerToDouble(T value) {
				return static_cast<double>(value);
			}

			template <typename T, typename U>
			static inline bool InRange(double d, T min, U max) {
				return d >= integerToDouble(min) && d <= integerToDouble(max);
			}
		#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)

			/** Duplicates the specified string value.
			* @param value Pointer to the string to duplicate. Must be zero-terminated if
			*              length is "unknown".
			* @param length Length of the value. if equals to unknown, then it will be
			*               computed using strlen(value).
			* @return Pointer on the duplicate instance of string.
			*/
			static inline char* duplicateStringValue(const char* value,
				size_t length) {
					// Avoid an integer overflow in the call to malloc below by limiting length
					// to a sane value.
					if (length >= (size_t)Value::maxInt)
						length = Value::maxInt - 1;

					char* newString = static_cast<char*>(malloc(length + 1));
					if (newString == NULL) {
						throwRuntimeError(
							"in Json::Value::duplicateStringValue(): "
							"Failed to allocate string value buffer");
					}
					memcpy(newString, value, length);
					newString[length] = 0;
					return newString;
			}

			/* Record the length as a prefix.
			*/
			static inline char* duplicateAndPrefixStringValue(
				const char* value,
				unsigned int length)
			{
				// Avoid an integer overflow in the call to malloc below by limiting length
				// to a sane value.
				JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U,
					"in Json::Value::duplicateAndPrefixStringValue(): "
					"length too big for prefixing");
				unsigned actualLength = length + sizeof(unsigned) + 1U;
				char* newString = static_cast<char*>(malloc(actualLength));
				if (newString == 0) {
					throwRuntimeError(
						"in Json::Value::duplicateAndPrefixStringValue(): "
						"Failed to allocate string value buffer");
				}
				*reinterpret_cast<unsigned*>(newString) = length;
				memcpy(newString + sizeof(unsigned), value, length);
				newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later
				return newString;
			}
			inline static void decodePrefixedString(
				bool isPrefixed, char const* prefixed,
				unsigned* length, char const** value)
			{
				if (!isPrefixed) {
					*length = strlen(prefixed);
					*value = prefixed;
				} else {
					*length = *reinterpret_cast<unsigned const*>(prefixed);
					*value = prefixed + sizeof(unsigned);
				}
			}
			/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue().
			*/
			static inline void releaseStringValue(char* value) { free(value); }

		// //////////////////////////////////////////////////////////////////
		// //////////////////////////////////////////////////////////////////
		// //////////////////////////////////////////////////////////////////
		// ValueInternals...
		// //////////////////////////////////////////////////////////////////
		// //////////////////////////////////////////////////////////////////
		// //////////////////////////////////////////////////////////////////
#include "valueiterator.inl"

			class Exception : public std::exception {
			public:
				Exception(std::string const& msg);
				virtual ~Exception() throw();
				virtual char const* what() const throw();
			protected:
				std::string const msg_;
			};
			class RuntimeError : public Exception {
			public:
				RuntimeError(std::string const& msg);
			};
			class LogicError : public Exception {
			public:
				LogicError(std::string const& msg);
			};

			Exception::Exception(std::string const& msg)
				: msg_(msg)
			{}
			Exception::~Exception() throw()
			{}
			char const* Exception::what() const throw()
			{
				return msg_.c_str();
			}
			RuntimeError::RuntimeError(std::string const& msg)
				: Exception(msg)
			{}
			LogicError::LogicError(std::string const& msg)
				: Exception(msg)
			{}
			void throwRuntimeError(std::string const& msg)
			{
				throw RuntimeError(msg);
			}
			void throwLogicError(std::string const& msg)
			{
				throw LogicError(msg);
			}

			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// class Value::CommentInfo
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////

			Value::CommentInfo::CommentInfo() : comment_(0) {}

			Value::CommentInfo::~CommentInfo() {
				if (comment_)
					releaseStringValue(comment_);
			}

			void Value::CommentInfo::setComment(const char* text, size_t len) {
				if (comment_) {
					releaseStringValue(comment_);
					comment_ = 0;
				}
				JSON_ASSERT(text != 0);
				JSON_ASSERT_MESSAGE(
					text[0] == '\0' || text[0] == '/',
					"in Json::Value::setComment(): Comments must start with /");
				// It seems that /**/ style comments are acceptable as well.
				comment_ = duplicateStringValue(text, len);
			}

			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// class Value::CZString
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////

			// Notes: policy_ indicates if the string was allocated when
			// a string is stored.

			Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {}

			Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate)
				: cstr_(str)
			{
				// allocate != duplicate
				storage_.policy_ = allocate;
				storage_.length_ = length;
			}

			Value::CZString::CZString(const CZString& other)
				: cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0
				? duplicateStringValue(other.cstr_, other.storage_.length_)
				: other.cstr_)
			{
				storage_.policy_ = (other.cstr_
					? (other.storage_.policy_ == noDuplication
					? noDuplication : duplicate)
					: other.storage_.policy_);
				storage_.length_ = other.storage_.length_;
			}

			Value::CZString::~CZString() {
				if (cstr_ && storage_.policy_ == duplicate)
					releaseStringValue(const_cast<char*>(cstr_));
			}

			void Value::CZString::swap(CZString& other) {
				std::swap(cstr_, other.cstr_);
				std::swap(index_, other.index_);
			}

			Value::CZString& Value::CZString::operator=(CZString other) {
				swap(other);
				return *this;
			}

			bool Value::CZString::operator<(const CZString& other) const {
				if (!cstr_) return index_ < other.index_;
				//return strcmp(cstr_, other.cstr_) < 0;
				// Assume both are strings.
				unsigned this_len = this->storage_.length_;
				unsigned other_len = other.storage_.length_;
				unsigned min_len = std::min(this_len, other_len);
				int comp = memcmp(this->cstr_, other.cstr_, min_len);
				if (comp < 0) return true;
				if (comp > 0) return false;
				return (this_len < other_len);
			}

			bool Value::CZString::operator==(const CZString& other) const {
				if (!cstr_) return index_ == other.index_;
				//return strcmp(cstr_, other.cstr_) == 0;
				// Assume both are strings.
				unsigned this_len = this->storage_.length_;
				unsigned other_len = other.storage_.length_;
				if (this_len != other_len) return false;
				int comp = memcmp(this->cstr_, other.cstr_, this_len);
				return comp == 0;
			}

			ArrayIndex Value::CZString::index() const { return index_; }

			//const char* Value::CZString::c_str() const { return cstr_; }
			const char* Value::CZString::data() const { return cstr_; }
			unsigned Value::CZString::length() const { return storage_.length_; }
			bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; }

			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// class Value::Value
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////
			// //////////////////////////////////////////////////////////////////

			/*! \internal Default constructor initialization must be equivalent to:
			* memset( this, 0, sizeof(Value) )
			* This optimization is used in ValueInternalMap fast allocator.
			*/
			Value::Value(ValueType type) {
				initBasic(type);
				switch (type) {
			case nullValue:
				break;
			case intValue:
			case uintValue:
				value_.int_ = 0;
				break;
			case realValue:
				value_.real_ = 0.0;
				break;
			case stringValue:
				value_.string_ = 0;
				break;
			case arrayValue:
			case objectValue:
				value_.map_ = new ObjectValues();
				break;
			case booleanValue:
				value_.bool_ = false;
				break;
			default:
				JSON_ASSERT_UNREACHABLE;
				}
			}

			Value::Value(Int value) {
				initBasic(intValue);
				value_.int_ = value;
			}

			Value::Value(UInt value) {
				initBasic(uintValue);
				value_.uint_ = value;
			}
#if defined(JSON_HAS_INT64)
			Value::Value(Int64 value) {
				initBasic(intValue);
				value_.int_ = value;
			}
			Value::Value(UInt64 value) {
				initBasic(uintValue);
				value_.uint_ = value;
			}
#endif // defined(JSON_HAS_INT64)

			Value::Value(double value) {
				initBasic(realValue);
				value_.real_ = value;
			}

			Value::Value(const char* value) {
				initBasic(stringValue, true);
				value_.string_ = duplicateAndPrefixStringValue(value, static_cast<unsigned>(strlen(value)));
			}

			Value::Value(const char* beginValue, const char* endValue) {
				initBasic(stringValue, true);
				value_.string_ =
					duplicateAndPrefixStringValue(beginValue, static_cast<unsigned>(endValue - beginValue));
			}

			Value::Value(const std::string& value) {
				initBasic(stringValue, true);
				value_.string_ =
					duplicateAndPrefixStringValue(value.data(), static_cast<unsigned>(value.length()));
			}

			Value::Value(const StaticString& value) {
				initBasic(stringValue);
				value_.string_ = const_cast<char*>(value.c_str());
			}


			Value::Value(bool value) {
				initBasic(booleanValue);
				value_.bool_ = value;
			}

			Value::Value(Value const& other)
				: type_(other.type_), allocated_(false)
				,
				comments_(0), start_(other.start_), limit_(other.limit_)
			{
				switch (type_) {
			case nullValue:
			case intValue:
			case uintValue:
			case realValue:
			case booleanValue:
				value_ = other.value_;
				break;
			case stringValue:
				if (other.value_.string_ && other.allocated_) {
					unsigned len;
					char const* str;
					decodePrefixedString(other.allocated_, other.value_.string_,
						&len, &str);
					value_.string_ = duplicateAndPrefixStringValue(str, len);
					allocated_ = true;
				} else {
					value_.string_ = other.value_.string_;
					allocated_ = false;
				}
				break;
			case arrayValue:
			case objectValue:
				value_.map_ = new ObjectValues(*other.value_.map_);
				break;
			default:
				JSON_ASSERT_UNREACHABLE;
				}
				if (other.comments_) {
					comments_ = new CommentInfo[numberOfCommentPlacement];
					for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
						const CommentInfo& otherComment = other.comments_[comment];
						if (otherComment.comment_)
							comments_[comment].setComment(
							otherComment.comment_, strlen(otherComment.comment_));
					}
				}
			}

			Value::~Value() {
				switch (type_) {
			case nullValue:
			case intValue:
			case uintValue:
			case realValue:
			case booleanValue:
				break;
			case stringValue:
				if (allocated_)
					releaseStringValue(value_.string_);
				break;
			case arrayValue:
			case objectValue:
				delete value_.map_;
				break;
			default:
				JSON_ASSERT_UNREACHABLE;
				}

				if (comments_)
					delete[] comments_;
			}

			Value& Value::operator=(Value other) {
				swap(other);
				return *this;
			}

			void Value::swapPayload(Value& other) {
				ValueType temp = type_;
				type_ = other.type_;
				other.type_ = temp;
				std::swap(value_, other.value_);
				int temp2 = allocated_;
				allocated_ = other.allocated_;
				other.allocated_ = temp2;
			}

			void Value::swap(Value& other) {
				swapPayload(other);
				std::swap(comments_, other.comments_);
				std::swap(start_, other.start_);
				std::swap(limit_, other.limit_);
			}

			ValueType Value::type() const { return type_; }

			int Value::compare(const Value& other) const {
				if (*this < other)
					return -1;
				if (*this > other)
					return 1;
				return 0;
			}

			bool Value::operator<(const Value& other) const {
				int typeDelta = type_ - other.type_;
				if (typeDelta)
					return typeDelta < 0 ? true : false;
				switch (type_) {
			case nullValue:
				return false;
			case intValue:
				return value_.int_ < other.value_.int_;
			case uintValue:
				return value_.uint_ < other.value_.uint_;
			case realValue:
				return value_.real_ < other.value_.real_;
			case booleanValue:
				return value_.bool_ < other.value_.bool_;
			case stringValue:
				{
					if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
						if (other.value_.string_) return true;
						else return false;
					}
					unsigned this_len;
					unsigned other_len;
					char const* this_str;
					char const* other_str;
					decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
					decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
					unsigned min_len = std::min(this_len, other_len);
					int comp = memcmp(this_str, other_str, min_len);
					if (comp < 0) return true;
					if (comp > 0) return false;
					return (this_len < other_len);
				}
			case arrayValue:
			case objectValue: {
				int delta = int(value_.map_->size() - other.value_.map_->size());
				if (delta)
					return delta < 0;
				return (*value_.map_) < (*other.value_.map_);
							  }
			default:
				JSON_ASSERT_UNREACHABLE;
				}
				return false; // unreachable
			}

			bool Value::operator<=(const Value& other) const { return !(other < *this); }

			bool Value::operator>=(const Value& other) const { return !(*this < other); }

			bool Value::operator>(const Value& other) const { return other < *this; }

			bool Value::operator==(const Value& other) const {
				// if ( type_ != other.type_ )
				// GCC 2.95.3 says:
				// attempt to take address of bit-field structure member `Json::Value::type_'
				// Beats me, but a temp solves the problem.
				int temp = other.type_;
				if (type_ != temp)
					return false;
				switch (type_) {
			case nullValue:
				return true;
			case intValue:
				return value_.int_ == other.value_.int_;
			case uintValue:
				return value_.uint_ == other.value_.uint_;
			case realValue:
				return value_.real_ == other.value_.real_;
			case booleanValue:
				return value_.bool_ == other.value_.bool_;
			case stringValue:
				{
					if ((value_.string_ == 0) || (other.value_.string_ == 0)) {
						return (value_.string_ == other.value_.string_);
					}
					unsigned this_len;
					unsigned other_len;
					char const* this_str;
					char const* other_str;
					decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
					decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str);
					if (this_len != other_len) return false;
					int comp = memcmp(this_str, other_str, this_len);
					return comp == 0;
				}
			case arrayValue:
			case objectValue:
				return value_.map_->size() == other.value_.map_->size() &&
					(*value_.map_) == (*other.value_.map_);
			default:
				JSON_ASSERT_UNREACHABLE;
				}
				return false; // unreachable
			}

			bool Value::operator!=(const Value& other) const { return !(*this == other); }

			const char* Value::asCString() const {
				JSON_ASSERT_MESSAGE(type_ == stringValue,
					"in Json::Value::asCString(): requires stringValue");
				if (value_.string_ == 0) return 0;
				unsigned this_len;
				char const* this_str;
				decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
				return this_str;
			}

			bool Value::getString(char const** str, char const** end) const {
				if (type_ != stringValue) return false;
				if (value_.string_ == 0) return false;
				unsigned length;
				decodePrefixedString(this->allocated_, this->value_.string_, &length, str);
				*end = *str + length;
				return true;
			}

			std::string Value::asString() const {
				switch (type_) {
			case nullValue:
				return "";
			case stringValue:
				{
					if (value_.string_ == 0) return "";
					unsigned this_len;
					char const* this_str;
					decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str);
					return std::string(this_str, this_len);
				}
			case booleanValue:
				return value_.bool_ ? "true" : "false";
			case intValue:
				return valueToString(value_.int_);
			case uintValue:
				return valueToString(value_.uint_);
			case realValue:
				return valueToString(value_.real_);
			default:
				JSON_FAIL_MESSAGE("Type is not convertible to string");
				}
			}


			Value::Int Value::asInt() const {
				switch (type_) {
			case intValue:
				JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
				return Int(value_.int_);
			case uintValue:
				JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
				return Int(value_.uint_);
			case realValue:
				JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
					"double out of Int range");
				return Int(value_.real_);
			case nullValue:
				return 0;
			case booleanValue:
				return value_.bool_ ? 1 : 0;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to Int.");
			}

			Value::UInt Value::asUInt() const {
				switch (type_) {
			case intValue:
				JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
				return UInt(value_.int_);
			case uintValue:
				JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
				return UInt(value_.uint_);
			case realValue:
				JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
					"double out of UInt range");
				return UInt(value_.real_);
			case nullValue:
				return 0;
			case booleanValue:
				return value_.bool_ ? 1 : 0;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
			}

#if defined(JSON_HAS_INT64)

			Value::Int64 Value::asInt64() const {
				switch (type_) {
			case intValue:
				return Int64(value_.int_);
			case uintValue:
				JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
				return Int64(value_.uint_);
			case realValue:
				JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
					"double out of Int64 range");
				return Int64(value_.real_);
			case nullValue:
				return 0;
			case booleanValue:
				return value_.bool_ ? 1 : 0;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
			}

			Value::UInt64 Value::asUInt64() const {
				switch (type_) {
			case intValue:
				JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
				return UInt64(value_.int_);
			case uintValue:
				return UInt64(value_.uint_);
			case realValue:
				JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
					"double out of UInt64 range");
				return UInt64(value_.real_);
			case nullValue:
				return 0;
			case booleanValue:
				return value_.bool_ ? 1 : 0;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
			}
#endif // if defined(JSON_HAS_INT64)

			LargestInt Value::asLargestInt() const {
#if defined(JSON_NO_INT64)
				return asInt();
#else
				return asInt64();
#endif
			}

			LargestUInt Value::asLargestUInt() const {
#if defined(JSON_NO_INT64)
				return asUInt();
#else
				return asUInt64();
#endif
			}

			double Value::asDouble() const {
				switch (type_) {
			case intValue:
				return static_cast<double>(value_.int_);
			case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
				return static_cast<double>(value_.uint_);
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
				return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
			case realValue:
				return value_.real_;
			case nullValue:
				return 0.0;
			case booleanValue:
				return value_.bool_ ? 1.0 : 0.0;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to double.");
			}

			float Value::asFloat() const {
				switch (type_) {
			case intValue:
				return static_cast<float>(value_.int_);
			case uintValue:
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
				return static_cast<float>(value_.uint_);
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
				return integerToDouble(value_.uint_);
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
			case realValue:
				return static_cast<float>(value_.real_);
			case nullValue:
				return 0.0;
			case booleanValue:
				return value_.bool_ ? 1.0f : 0.0f;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to float.");
			}

			bool Value::asBool() const {
				switch (type_) {
			case booleanValue:
				return value_.bool_;
			case nullValue:
				return false;
			case intValue:
				return value_.int_ ? true : false;
			case uintValue:
				return value_.uint_ ? true : false;
			case realValue:
				return value_.real_ ? true : false;
			default:
				break;
				}
				JSON_FAIL_MESSAGE("Value is not convertible to bool.");
			}

			bool Value::isConvertibleTo(ValueType other) const {
				switch (other) {
			case nullValue:
				return (isNumeric() && asDouble() == 0.0) ||
					(type_ == booleanValue && value_.bool_ == false) ||
					(type_ == stringValue && asString() == "") ||
					(type_ == arrayValue && value_.map_->size() == 0) ||
					(type_ == objectValue && value_.map_->size() == 0) ||
					type_ == nullValue;
			case intValue:
				return isInt() ||
					(type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
					type_ == booleanValue || type_ == nullValue;
			case uintValue:
				return isUInt() ||
					(type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
					type_ == booleanValue || type_ == nullValue;
			case realValue:
				return isNumeric() || type_ == booleanValue || type_ == nullValue;
			case booleanValue:
				return isNumeric() || type_ == booleanValue || type_ == nullValue;
			case stringValue:
				return isNumeric() || type_ == booleanValue || type_ == stringValue ||
					type_ == nullValue;
			case arrayValue:
				return type_ == arrayValue || type_ == nullValue;
			case objectValue:
				return type_ == objectValue || type_ == nullValue;
				}
				JSON_ASSERT_UNREACHABLE;
				return false;
			}

			/// Number of values in array or object
			ArrayIndex Value::size() const {
				switch (type_) {
			case nullValue:
			case intValue:
			case uintValue:
			case realValue:
			case booleanValue:
			case stringValue:
				return 0;
			case arrayValue: // size of the array is highest index + 1
				if (!value_.map_->empty()) {
					ObjectValues::const_iterator itLast = value_.map_->end();
					--itLast;
					return (*itLast).first.index() + 1;
				}
				return 0;
			case objectValue:
				return ArrayIndex(value_.map_->size());
				}
				JSON_ASSERT_UNREACHABLE;
				return 0; // unreachable;
			}

			bool Value::empty() const {
				if (isNull() || isArray() || isObject())
					return size() == 0u;
				else
					return false;
			}

			bool Value::operator!() const { return isNull(); }

			void Value::clear() {
				JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
					type_ == objectValue,
					"in Json::Value::clear(): requires complex value");
				start_ = 0;
				limit_ = 0;
				switch (type_) {
			case arrayValue:
			case objectValue:
				value_.map_->clear();
				break;
			default:
				break;
				}
			}

			void Value::resize(ArrayIndex newSize) {
				JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
					"in Json::Value::resize(): requires arrayValue");
				if (type_ == nullValue)
					*this = Value(arrayValue);
				ArrayIndex oldSize = size();
				if (newSize == 0)
					clear();
				else if (newSize > oldSize)
					(*this)[newSize - 1];
				else {
					for (ArrayIndex index = newSize; index < oldSize; ++index) {
						value_.map_->erase(index);
					}
					assert(size() == newSize);
				}
			}

			Value& Value::operator[](ArrayIndex index) {
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == arrayValue,
					"in Json::Value::operator[](ArrayIndex): requires arrayValue");
				if (type_ == nullValue)
					*this = Value(arrayValue);
				CZString key(index);
				ObjectValues::iterator it = value_.map_->lower_bound(key);
				if (it != value_.map_->end() && (*it).first == key)
					return (*it).second;

				ObjectValues::value_type defaultValue(key, nullRef);
				it = value_.map_->insert(it, defaultValue);
				return (*it).second;
			}

			Value& Value::operator[](int index) {
				JSON_ASSERT_MESSAGE(
					index >= 0,
					"in Json::Value::operator[](int index): index cannot be negative");
				return (*this)[ArrayIndex(index)];
			}

			const Value& Value::operator[](ArrayIndex index) const {
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == arrayValue,
					"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
				if (type_ == nullValue)
					return nullRef;
				CZString key(index);
				ObjectValues::const_iterator it = value_.map_->find(key);
				if (it == value_.map_->end())
					return nullRef;
				return (*it).second;
			}

			const Value& Value::operator[](int index) const {
				JSON_ASSERT_MESSAGE(
					index >= 0,
					"in Json::Value::operator[](int index) const: index cannot be negative");
				return (*this)[ArrayIndex(index)];
			}

			void Value::initBasic(ValueType type, bool allocated) {
				type_ = type;
				allocated_ = allocated;
				comments_ = 0;
				start_ = 0;
				limit_ = 0;
			}

			// Access an object value by name, create a null member if it does not exist.
			// @pre Type of '*this' is object or null.
			// @param key is null-terminated.
			Value& Value::resolveReference(const char* key) {
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == objectValue,
					"in Json::Value::resolveReference(): requires objectValue");
				if (type_ == nullValue)
					*this = Value(objectValue);
				CZString actualKey(
					key, static_cast<unsigned>(strlen(key)), CZString::noDuplication); // NOTE!
				ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
				if (it != value_.map_->end() && (*it).first == actualKey)
					return (*it).second;

				ObjectValues::value_type defaultValue(actualKey, nullRef);
				it = value_.map_->insert(it, defaultValue);
				Value& value = (*it).second;
				return value;
			}

			// @param key is not null-terminated.
			Value& Value::resolveReference(char const* key, char const* end)
			{
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == objectValue,
					"in Json::Value::resolveReference(key, end): requires objectValue");
				if (type_ == nullValue)
					*this = Value(objectValue);
				CZString actualKey(
					key, static_cast<unsigned>(end-key), CZString::duplicateOnCopy);
				ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
				if (it != value_.map_->end() && (*it).first == actualKey)
					return (*it).second;

				ObjectValues::value_type defaultValue(actualKey, nullRef);
				it = value_.map_->insert(it, defaultValue);
				Value& value = (*it).second;
				return value;
			}

			Value Value::get(ArrayIndex index, const Value& defaultValue) const {
				const Value* value = &((*this)[index]);
				return value == &nullRef ? defaultValue : *value;
			}

			bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }

			Value const* Value::find(char const* key, char const* end) const
			{
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == objectValue,
					"in Json::Value::find(key, end, found): requires objectValue or nullValue");
				if (type_ == nullValue) return NULL;
				CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
				ObjectValues::const_iterator it = value_.map_->find(actualKey);
				if (it == value_.map_->end()) return NULL;
				return &(*it).second;
			}
			const Value& Value::operator[](const char* key) const
			{
				Value const* found = find(key, key + strlen(key));
				if (!found) return nullRef;
				return *found;
			}
			Value const& Value::operator[](std::string const& key) const
			{
				Value const* found = find(key.data(), key.data() + key.length());
				if (!found) return nullRef;
				return *found;
			}

			Value& Value::operator[](const char* key) {
				return resolveReference(key, key + strlen(key));
			}

			Value& Value::operator[](const std::string& key) {
				return resolveReference(key.data(), key.data() + key.length());
			}

			Value& Value::operator[](const StaticString& key) {
				return resolveReference(key.c_str());
			}


			Value& Value::append(const Value& value) { return (*this)[size()] = value; }

			Value Value::get(char const* key, char const* end, Value const& defaultValue) const
			{
				Value const* found = find(key, end);
				return !found ? defaultValue : *found;
			}
			Value Value::get(char const* key, Value const& defaultValue) const
			{
				return get(key, key + strlen(key), defaultValue);
			}
			Value Value::get(std::string const& key, Value const& defaultValue) const
			{
				return get(key.data(), key.data() + key.length(), defaultValue);
			}


			bool Value::removeMember(const char* key, const char* end, Value* removed)
			{
				if (type_ != objectValue) {
					return false;
				}
				CZString actualKey(key, static_cast<unsigned>(end-key), CZString::noDuplication);
				ObjectValues::iterator it = value_.map_->find(actualKey);
				if (it == value_.map_->end())
					return false;
				*removed = it->second;
				value_.map_->erase(it);
				return true;
			}
			bool Value::removeMember(const char* key, Value* removed)
			{
				return removeMember(key, key + strlen(key), removed);
			}
			bool Value::removeMember(std::string const& key, Value* removed)
			{
				return removeMember(key.data(), key.data() + key.length(), removed);
			}
			Value Value::removeMember(const char* key)
			{
				JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
					"in Json::Value::removeMember(): requires objectValue");
				if (type_ == nullValue)
					return nullRef;

				Value removed;  // null
				removeMember(key, key + strlen(key), &removed);
				return removed; // still null if removeMember() did nothing
			}
			Value Value::removeMember(const std::string& key)
			{
				return removeMember(key.c_str());
			}

			bool Value::removeIndex(ArrayIndex index, Value* removed) {
				if (type_ != arrayValue) {
					return false;
				}
				CZString key(index);
				ObjectValues::iterator it = value_.map_->find(key);
				if (it == value_.map_->end()) {
					return false;
				}
				*removed = it->second;
				ArrayIndex oldSize = size();
				// shift left all items left, into the place of the "removed"
				for (ArrayIndex i = index; i < (oldSize - 1); ++i){
					CZString key(i);
					(*value_.map_)[key] = (*this)[i + 1];
				}
				// erase the last one ("leftover")
				CZString keyLast(oldSize - 1);
				ObjectValues::iterator itLast = value_.map_->find(keyLast);
				value_.map_->erase(itLast);
				return true;
			}

			bool Value::isMember(char const* key, char const* end) const
			{
				Value const* value = find(key, end);
				return NULL != value;
			}
			bool Value::isMember(char const* key) const
			{
				return isMember(key, key + strlen(key));
			}
			bool Value::isMember(std::string const& key) const
			{
				return isMember(key.data(), key.data() + key.length());
			}


			Value::Members Value::getMemberNames() const {
				JSON_ASSERT_MESSAGE(
					type_ == nullValue || type_ == objectValue,
					"in Json::Value::getMemberNames(), value must be objectValue");
				if (type_ == nullValue)
					return Value::Members();
				Members members;
				members.reserve(value_.map_->size());
				ObjectValues::const_iterator it = value_.map_->begin();
				ObjectValues::const_iterator itEnd = value_.map_->end();
				for (; it != itEnd; ++it) {
					members.push_back(std::string((*it).first.data(),
						(*it).first.length()));
				}
				return members;
			}

			static bool IsIntegral(double d) {
				double integral_part;
				return modf(d, &integral_part) == 0.0;
			}

			bool Value::isNull() const { return type_ == nullValue; }

			bool Value::isBool() const { return type_ == booleanValue; }

			bool Value::isInt() const {
				switch (type_) {
			case intValue:
				return value_.int_ >= minInt && value_.int_ <= maxInt;
			case uintValue:
				return value_.uint_ <= UInt(maxInt);
			case realValue:
				return value_.real_ >= minInt && value_.real_ <= maxInt &&
					IsIntegral(value_.real_);
			default:
				break;
				}
				return false;
			}

			bool Value::isUInt() const {
				switch (type_) {
			case intValue:
				return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
			case uintValue:
				return value_.uint_ <= maxUInt;
			case realValue:
				return value_.real_ >= 0 && value_.real_ <= maxUInt &&
					IsIntegral(value_.real_);
			default:
				break;
				}
				return false;
			}

			bool Value::isInt64() const {
#if defined(JSON_HAS_INT64)
				switch (type_) {
			case intValue:
				return true;
			case uintValue:
				return value_.uint_ <= UInt64(maxInt64);
			case realValue:
				// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
				// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
				// require the value to be strictly less than the limit.
				return value_.real_ >= double(minInt64) &&
					value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
			default:
				break;
				}
#endif // JSON_HAS_INT64
				return false;
			}

			bool Value::isUInt64() const {
#if defined(JSON_HAS_INT64)
				switch (type_) {
			case intValue:
				return value_.int_ >= 0;
			case uintValue:
				return true;
			case realValue:
				// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
				// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
				// require the value to be strictly less than the limit.
				return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
					IsIntegral(value_.real_);
			default:
				break;
				}
#endif // JSON_HAS_INT64
				return false;
			}

			bool Value::isIntegral() const {
#if defined(JSON_HAS_INT64)
				return isInt64() || isUInt64();
#else
				return isInt() || isUInt();
#endif
			}

			bool Value::isDouble() const { return type_ == realValue || isIntegral(); }

			bool Value::isNumeric() const { return isIntegral() || isDouble(); }

			bool Value::isString() const { return type_ == stringValue; }

			bool Value::isArray() const { return type_ == arrayValue; }

			bool Value::isObject() const { return type_ == objectValue; }

			void Value::setComment(const char* comment, size_t len, CommentPlacement placement) {
				if (!comments_)
					comments_ = new CommentInfo[numberOfCommentPlacement];
				if ((len > 0) && (comment[len-1] == '\n')) {
					// Always discard trailing newline, to aid indentation.
					len -= 1;
				}
				comments_[placement].setComment(comment, len);
			}

			void Value::setComment(const char* comment, CommentPlacement placement) {
				setComment(comment, strlen(comment), placement);
			}

			void Value::setComment(const std::string& comment, CommentPlacement placement) {
				setComment(comment.c_str(), comment.length(), placement);
			}

			bool Value::hasComment(CommentPlacement placement) const {
				return comments_ != 0 && comments_[placement].comment_ != 0;
			}

			std::string Value::getComment(CommentPlacement placement) const {
				if (hasComment(placement))
					return comments_[placement].comment_;
				return "";
			}

			void Value::setOffsetStart(size_t start) { start_ = start; }

			void Value::setOffsetLimit(size_t limit) { limit_ = limit; }

			size_t Value::getOffsetStart() const { return start_; }

			size_t Value::getOffsetLimit() const { return limit_; }

			std::string Value::toStyledString() const {
				StyledWriter writer;
				return writer.write(*this);
			}

			Value::const_iterator Value::begin() const {
				switch (type_) {
			case arrayValue:
			case objectValue:
				if (value_.map_)
					return const_iterator(value_.map_->begin());
				break;
			default:
				break;
				}
				return const_iterator();
			}

			Value::const_iterator Value::end() const {
				switch (type_) {
			case arrayValue:
			case objectValue:
				if (value_.map_)
					return const_iterator(value_.map_->end());
				break;
			default:
				break;
				}
				return const_iterator();
			}

			Value::iterator Value::begin() {
				switch (type_) {
			case arrayValue:
			case objectValue:
				if (value_.map_)
					return iterator(value_.map_->begin());
				break;
			default:
				break;
				}
				return iterator();
			}

			Value::iterator Value::end() {
				switch (type_) {
			case arrayValue:
			case objectValue:
				if (value_.map_)
					return iterator(value_.map_->end());
				break;
			default:
				break;
				}
				return iterator();
			}

			// class PathArgument
			// //////////////////////////////////////////////////////////////////

			PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}

			PathArgument::PathArgument(ArrayIndex index)
				: key_(), index_(index), kind_(kindIndex) {}

			PathArgument::PathArgument(const char* key)
				: key_(key), index_(), kind_(kindKey) {}

			PathArgument::PathArgument(const std::string& key)
				: key_(key.c_str()), index_(), kind_(kindKey) {}

			// class Path
			// //////////////////////////////////////////////////////////////////

			Path::Path(const std::string& path,
				const PathArgument& a1,
				const PathArgument& a2,
				const PathArgument& a3,
				const PathArgument& a4,
				const PathArgument& a5) {
					InArgs in;
					in.push_back(&a1);
					in.push_back(&a2);
					in.push_back(&a3);
					in.push_back(&a4);
					in.push_back(&a5);
					makePath(path, in);
			}

			void Path::makePath(const std::string& path, const InArgs& in) {
				const char* current = path.c_str();
				const char* end = current + path.length();
				InArgs::const_iterator itInArg = in.begin();
				while (current != end) {
					if (*current == '[') {
						++current;
						if (*current == '%')
							addPathInArg(path, in, itInArg, PathArgument::kindIndex);
						else {
							ArrayIndex index = 0;
							for (; current != end && *current >= '0' && *current <= '9'; ++current)
								index = index * 10 + ArrayIndex(*current - '0');
							args_.push_back(index);
						}
						if (current == end || *current++ != ']')
							invalidPath(path, int(current - path.c_str()));
					} else if (*current == '%') {
						addPathInArg(path, in, itInArg, PathArgument::kindKey);
						++current;
					} else if (*current == '.') {
						++current;
					} else {
						const char* beginName = current;
						while (current != end && !strchr("[.", *current))
							++current;
						args_.push_back(std::string(beginName, current));
					}
				}
			}

			void Path::addPathInArg(const std::string& /*path*/,
				const InArgs& in,
				InArgs::const_iterator& itInArg,
				PathArgument::Kind kind) {
					if (itInArg == in.end()) {
						// Error: missing argument %d
					} else if ((*itInArg)->kind_ != kind) {
						// Error: bad argument type
					} else {
						args_.push_back(**itInArg);
					}
			}

			void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
				// Error: invalid path.
			}

			const Value& Path::resolve(const Value& root) const {
				const Value* node = &root;
				for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
					const PathArgument& arg = *it;
					if (arg.kind_ == PathArgument::kindIndex) {
						if (!node->isArray() || !node->isValidIndex(arg.index_)) {
							// Error: unable to resolve path (array value expected at position...
						}
						node = &((*node)[arg.index_]);
					} else if (arg.kind_ == PathArgument::kindKey) {
						if (!node->isObject()) {
							// Error: unable to resolve path (object value expected at position...)
						}
						node = &((*node)[arg.key_]);
						if (node == &Value::nullRef) {
							// Error: unable to resolve path (object has no member named '' at
							// position...)
						}
					}
				}
				return *node;
			}

			Value Path::resolve(const Value& root, const Value& defaultValue) const {
				const Value* node = &root;
				for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
					const PathArgument& arg = *it;
					if (arg.kind_ == PathArgument::kindIndex) {
						if (!node->isArray() || !node->isValidIndex(arg.index_))
							return defaultValue;
						node = &((*node)[arg.index_]);
					} else if (arg.kind_ == PathArgument::kindKey) {
						if (!node->isObject())
							return defaultValue;
						node = &((*node)[arg.key_]);
						if (node == &Value::nullRef)
							return defaultValue;
					}
				}
				return *node;
			}

			Value& Path::make(Value& root) const 
			{
				Value* node = &root;
				for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
					const PathArgument& arg = *it;
					if (arg.kind_ == PathArgument::kindIndex) {
						if (!node->isArray()) {
							// Error: node is not an array at position ...
						}
						node = &((*node)[arg.index_]);
					} else if (arg.kind_ == PathArgument::kindKey) {
						if (!node->isObject()) {
							// Error: node is not an object at position...
						}
						node = &((*node)[arg.key_]);
					}
				}
				return *node;
			}
		}//end namespace jsoncpp
	}//end namespace json
}//end namespace JHCPP